//
//  HenryController.m
//  Henry
//
//  Created by Ron Olson on 3/9/10.
//  Copyright 2010 Keep Bertha Surfin. All rights reserved.
//

#import "HenryController.h"
#import "GPXParser.h"
#import "ClockwiseTraveler.h"

@implementation HenryController

-(id)init
{
	[super init];
	
	/* The default mode of travel is walking */
	modeOfTravel = 1;
	
	/* Initialize our list position */
	currentPosInList = 0;
	
	/* Initialize our table view */
	tableView = [[NSTableView alloc] init];
	
	return self;
}

-(void)awakeFromNib
{
	[steppingField setStringValue:@"2"];	
	
	[webView setDrawsBackground:NO];
    [webView setUIDelegate:self];
    [webView setFrameLoadDelegate:self];
	[[webView windowScriptObject] setValue:self forKey:@"HenryController"];
}

/*
 * This is where everything is done
 */
-(IBAction)createTour:(id)sender
{
	GPXParser *gpxParser = [[GPXParser alloc] initWithGPXFilename:[fileNameField stringValue]];
	NSArray *loadedWaypoints = [gpxParser processFile];
	
	ClockwiseTraveler *traveler = [[ClockwiseTraveler alloc] initWithWaypoints:loadedWaypoints startingAt:[loadedWaypoints objectAtIndex:0]];
	
	sortedWaypoints = [traveler getSortedWaypoints];
	
	/* More than two waypoints? */
	if ([sortedWaypoints count] < 2)
	{
		/* Guess not */
		NSRunAlertPanel(@"Not enough waypoints", @"At least two waypoints are necessary for the map", @"Ok", nil, nil);
	}
	else 
	{
		/* Yep, so we need to pass them on to the html page */
		[tableView reloadData];
		
		/* And the webpage */
		NSString *resourcesPath = [[NSBundle mainBundle] resourcePath];
		NSString *htmlPath = [resourcesPath stringByAppendingString:@"/map.html"];
		[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]];			
	}
}

/*
 * For the table view, we need both numberOfRowsInTableView and objectValueForTableColumn
 * because HenryController is marked as the dataSource
 */
-(NSInteger)numberOfRowsInTableView:(NSTableView*)tv
{
	return [sortedWaypoints count];
}

-(id)tableView:(NSTableView*)tv objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
	if ([[tableColumn identifier] isEqualToString:@"nameCol"]) 
	{
		return [[sortedWaypoints objectAtIndex:row] wptName];	
	}

	if ([[tableColumn identifier] isEqualToString:@"descCol"]) 
	{
		return [[sortedWaypoints objectAtIndex:row] wptDescription];	
	}
	
	return NULL;
}

/*
 * Selects the GPX file from the Open File dialog
 */
-(IBAction)openGPXFile:(id)sender
{
	int i;
	
	NSOpenPanel* openDlg = [NSOpenPanel openPanel];
	[openDlg setCanChooseFiles:YES];
	[openDlg setCanChooseDirectories:NO];
	
	if ([openDlg runModalForDirectory:nil file:nil] == NSOKButton)
	{
		NSArray* files = [openDlg filenames];
		for( i = 0; i < [files count]; i++ )
		{
			NSString* fileName = [files objectAtIndex:i];
			[fileNameField setStringValue:fileName];
		}
	}	
}

-(IBAction)setTransportType:(id)sender
{
	NSButtonCell *selCell = [sender selectedCell];
 	
	if ([selCell tag] == 1)
	{
		/* They chose walking */
		modeOfTravel = 1;
	}
	else 
	{
		/* They chose driving */
		modeOfTravel = 0;
	}
}

-(IBAction)setStepping:(id)sender
{
	[steppingField setIntValue:[sender intValue]];
}


+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
{
	if (aSelector == @selector(goForward:)) 
	{
        return NO;
    }
	else if (aSelector == @selector(goBack:))
	{
		return NO;
	}
    
    return YES; // disallow everything else	
}

+ (BOOL)isKeyExcludedFromWebScript:(const char *)name
{
	return NO;
}

/*
 * NOTE! This method does *not* return an array of points, but rather, wraps the
 * array of points in another array, because it's being sent to a Javascript
 * function, which expects an array of objects (i.e. all the possible parameters
 * that can be sent to it).
 */
-(NSArray*)waypointsToShow:(bool)forward
{
	/* Our stepping */
	int stepping = [steppingField intValue];
		
	/* Sanity checking */
	if (forward == false)
	{
		if (currentPosInList < stepping)
			currentPosInList = 0;
		else
			currentPosInList -= stepping;
	}
	else 
	{
		if (currentPosInList + stepping >= [sortedWaypoints count])
		{
			NSLog(@"Last Page");
			NSRunAlertPanel(@"Sorry...", @"Last page!", nil, nil, nil);
		}
		else 
		{
			currentPosInList += stepping;
		}
	}
	
	
	NSMutableArray *wayPoints = [[NSMutableArray alloc] init];
	/*
	 * Now we'll actually load the array of waypoints we want directions for
	 */
	for (int wptRow = 0; wptRow < stepping; ++wptRow)
	{
		[wayPoints addObject:[[sortedWaypoints objectAtIndex:wptRow + currentPosInList] getFormattedWPForGoogleMaps]];
	}
	
	/* 
	 * Note that we have to wrap our array, created above, in *another* array, because
	 * its *this* array that represents all the parameters that can be passed to the 
	 * Javascript function.
	 */
	NSArray *args = [NSArray arrayWithObjects:wayPoints, modeOfTravel == 1 ? @"w" : @"d", nil];
	
	return args;
}

/* Will be invoked at the end of the load of the page, so we can then invoke the javascript */
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
	/* As this is being called from the initial load, we can say we want to go forward */
	[[sender windowScriptObject] callWebScriptMethod:@"setDirectionsFromArray" withArguments:[self waypointsToShow:true]];
}


- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element 
    defaultMenuItems:(NSArray *)defaultMenuItems
{
    return nil; // disable contextual menu for the webView
}

- (void)goBack:(NSString*)notUsed;
{
	WebScriptObject *scriptObject = [webView windowScriptObject];
	[scriptObject callWebScriptMethod:@"setDirectionsFromArray" withArguments:[self waypointsToShow:false]];    
}

- (void)goForward:(NSString*)notUsed
{
	WebScriptObject *scriptObject = [webView windowScriptObject];
	[scriptObject callWebScriptMethod:@"setDirectionsFromArray" withArguments:[self waypointsToShow:true]];
}


/* For printing */
-(IBAction)printMap:(id)sender
{
	NSView *printView = [[[webView mainFrame] frameView] documentView];
    
	NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
    [printInfo setVerticallyCentered:NO]; 
    [printInfo setHorizontalPagination:NSFitPagination];
    
    NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:printView];
    [printOperation runOperation];
}

/* Save the sorted waypoints to a GPX file */
-(IBAction)saveSortedWaypointsToGPX:(id)sender
{
	NSXMLElement *root = [[NSXMLElement alloc] initWithName:@"gpx"];
	[root addChild:[NSXMLNode commentWithStringValue:@"The waypoints in this list are sorted based on a TSP algorithm created by Henry"]];
	[root addChild:[NSXMLNode commentWithStringValue:@"See http://code.google.com/p/geotripplanner/ for more information "]];
	
	NSXMLDocument *doc = [[NSXMLDocument alloc] initWithRootElement:root];
	[doc setVersion:@"1.0"];
	[doc setCharacterEncoding:@"UTF-8"];
	
	[root release];
	
	/* Now let's add some real data */
	for (int pos = 0; pos < [sortedWaypoints count]; ++pos)
	{
		Waypoint* currentWaypoint = [sortedWaypoints objectAtIndex:pos];
		
		/* Set up the waypoint element with the attributes for the latitude and longitude */
		NSXMLElement *wpt = [[NSXMLElement alloc] initWithName:@"wpt"];
		[wpt addAttribute:[NSXMLNode attributeWithName:@"lat" stringValue:[NSString stringWithFormat:@"%f", [currentWaypoint latitude]]]];
		[wpt addAttribute:[NSXMLNode attributeWithName:@"lon" stringValue:[NSString stringWithFormat:@"%f", [currentWaypoint longitude]]]];
		
		/* Now we add a separate element for the name */
		NSXMLElement *wptName = [NSXMLElement elementWithName:@"name"];
		[wptName setStringValue:[currentWaypoint wptName]];

		/* And do likewise for the description */
		NSXMLElement *wptDescription = [NSXMLElement elementWithName:@"desc"];
		[wptDescription setStringValue:[currentWaypoint wptDescription]];
		
		/* And add them to our current element */
		[wpt addChild:wptName];
		[wpt addChild:wptDescription];
		
		/* Add it to our big list o' elements */
		[root addChild:wpt];
		
		/* And clean up */
		[wptDescription release];
		[wptName release];
		[wpt release];
	}
		
	/* Temporary ... will ask for the filename in Save As... */
	NSData *xmlData = [doc XMLDataWithOptions:NSXMLNodePrettyPrint];
	[xmlData writeToFile:[@"~/Desktop/sortedwaypoints.xml" stringByExpandingTildeInPath] atomically:YES];
	
	[doc release];	
}

@end
